#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <math.h>
#include "Game.h"
#include "Thread.hpp"
#include <time.h>

char		_running = 0;

typedef void*	(*ThreadFct)(void*);

void*		startKeyManaging(void* ag)
{
  Game*		game = static_cast<Game*>(ag);
  struct timespec start, finish;
  double elapsed;

  clock_gettime(CLOCK_MONOTONIC, &start);
  while (game->manage_keys())
    {
      clock_gettime(CLOCK_MONOTONIC, &finish);
      elapsed = (finish.tv_sec - start.tv_sec);
      elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
      if (elapsed >= 0.1)
	{
	  clock_gettime(CLOCK_MONOTONIC, &start);
	  SDL_WM_SetCaption(game->getTitle(), NULL);
	}
      usleep(5000);
    }
  std::cout << "END.\n";
  _running = 2;
  return NULL;
}

int		main(int ac, char** av)
{
  srand(time(NULL));
  std::cout << "Loading";

  if (ac < 1)
    {
      std::cout << "Usage: cmd <>" << std::endl;
      return 0;
    }

  Game		g(1);
  unsigned int	_sleep_time = 0;

  _running = 1;
   if (ac > 2)
    _sleep_time = atoi(av[2]);
  std::cout << std::endl;
  g.init_SDL();

  std::cout.setf(std::ios::fixed, std::ios::floatfield);
  std::cout.precision(10);

  AThread	thread;
  thread.start((Routine)(startKeyManaging), static_cast<void*>(&g));

  // Definition du repere
  long double	xrbmin = -2.1;
  long double	xrbmax = 0.6;
  long double	yrbmin = -1.2;
  long double	yrbmax = 1.2;
  int		itmax = 255;

  // Correcteur de repere
  long double	xrblen = xrbmax - xrbmin;
  long double	yrblen = yrbmax - yrbmin;
  if (xrblen > yrblen)
    yrbmax = yrbmin + xrblen;
  else if (xrblen < yrblen)
    xrbmax = xrbmin + yrblen;
  // Correcteur de camera
  if (_xdim > _ydim)
    xrbmax = xrbmin + (yrbmax - yrbmin)*_xdim/_ydim;
  else if (_xdim < _ydim)
    yrbmax = (xrbmax - xrbmin)*_ydim/_xdim;

  // BOUCLE P
  while (_running != 2)
    {
      // Application du zoom avec la camera
      long double	xrmin = (xrbmax - xrbmin)*(g.getCam().x)/_xdim + xrbmin;
      long double	yrmin = (yrbmax - yrbmin)*(g.getCam().y)/_ydim + yrbmin;
      long double	xrmax = xrmin + (xrbmax - xrbmin)/(long double)g.getZoom();
      long double	yrmax = yrmin + (yrbmax - yrbmin)/(long double)g.getZoom();
      long double	xzoom = _xdim/(xrmax - xrmin);
      long double	yzoom = _ydim/(yrmax - yrmin);
      //      std::cin >> xzoom;
      std::cout << "xrmin=" << xrmin << " yrmin=" << yrmin << " xrmax=" << xrmax << " yrmax=" << yrmax << " zoom=" << g.getZoom() << std::endl;

      for (int x = 0; x < _xdim; ++x)
	{
	  //	  if (x % (_xdim / 10) == 0)
	    {
	      sprintf(g.getTitle(), "Fractahl - %d%%", (int)x*100/_xdim);
	    }
	  for (int y = 0; y < _ydim; ++y)
	    {
	      long double	cr = 0.285;
	      long double	ci = 0.01;
	      long double	zr = x/xzoom + xrmin;
	      long double	zi = y/yzoom + yrmin;
	      int	i;
	      for (i = 0; i < itmax; ++i)
		{
		  long double	tmpzr = zr;
		  zr = zr*zr - zi*zi + cr;
		  zi = 2*zi*tmpzr + ci;
		  if (zr*zr + zi*zi >= 4)
		      break;
		}
	      
	      if (i == itmax)
		g.dot32(x, y, SDL_MapRGB(SDL_GetVideoSurface()->format, 0, 0, 100));
	      else
		g.dot32(x, y, SDL_MapRGB(SDL_GetVideoSurface()->format, 0, i * 2, 0));
	    }
	  while (g.paused() && !(_running == 2))
	    usleep(100000);
	}
      // maintainers
      sprintf(g.getTitle(), "Fractahl");
      if (_sleep_time)
	usleep(_sleep_time);
      g.sync();
      //g.cls();
      if (_verb)
	std::cout << "-----------------Refreshed-----------------" << std::endl;
      // Attente d'une action
      int	currentZoom = g.getZoom();
      Coord	currentCam = g.getCam();
      while (currentZoom == g.getZoom() && currentCam.x == g.getCam().x && currentCam.y == g.getCam().y)
	{
	  usleep(100000);
	  if (_running == 2)
	    return 0;
	}
    }
  return 0;
}
